﻿



Public Class ThreadExceptionHandler

    Dim CrashMessage As String
    '''
    ''' Handles the thread exception.
    '''
    Public Sub Application_ThreadException( _
        ByVal sender As System.Object, _
        ByVal e As System.Threading.ThreadExceptionEventArgs)

        


        Try

            Select Case ShowThreadExceptionDialog(e.Exception)
                Case DialogResult.OK
                    Dim x As New Formition.FormitionPasswordSafe

                    If Not TestMode Then
                        x.Url = "http://www.formition.com/desktopmodules/formition/formitionpasswordsafe.asmx"
                        x.Credentials = System.Net.CredentialCache.DefaultCredentials
                        x.Proxy = System.Net.WebProxy.GetDefaultProxy
                        x.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials
                        System.Net.ServicePointManager.Expect100Continue = False
                    End If

                    Dim SecurityToken As String = Common.Encrypt(Common.SystemKey, "Formition Password Safe")


                    'try 3 times to capture the message
                    Try
                        x.LogError(SecurityToken, Common.RegistrationID, CrashMessage)
                        Call MsgBox("Thankyou, the data has finished being uploaded to the webserver.")
                    Catch ex1 As Exception
                        Try
                            x.LogError(SecurityToken, Common.RegistrationID, CrashMessage)
                            Call MsgBox("Thankyou, the data has finished being uploaded to the webserver.")
                        Catch ex2 As Exception
                            Try
                                x.LogError(SecurityToken, Common.RegistrationID, CrashMessage)
                                Call MsgBox("Thankyou, the data has finished being uploaded to the webserver.")
                            Catch ex3 As Exception
                                Call MsgBox(ex3.Message)
                            End Try
                        End Try
                    End Try


            End Select



            'need to stop the program from continuing somehow here....
            'this will prevent the "are you sure" from popping up when exiting.
            Common.BackgroundDataLoadingIgnoreEvents = True

            Application.Exit()

        Catch
            ' Fatal error, terminate program
            Try
                MessageBox.Show("Fatal Error", _
                    "Fatal Error", _
                    MessageBoxButtons.OK, _
                    MessageBoxIcon.Stop)
            Finally
                Application.Exit()
            End Try
        End Try
    End Sub

    '''
    ''' Creates and displays the error message.
    '''
    Private Function ShowThreadExceptionDialog( _
        ByVal ex As Exception) As DialogResult


        Dim Version As String = Passwords.VersionPasswordSafe
        Dim SystemType As String = System.Environment.OSVersion.Platform & " (" & System.Environment.OSVersion.ServicePack & ")" & " " & System.Environment.OSVersion.VersionString

        CrashMessage = "An unhandled exception occurred. In order to improve this product please click OK to send the debug information to the support team." & vbCrLf & _
            vbCrLf & "SoftwareVersion: " & Version & vbCrLf & "System Info: " & SystemType & vbCrLf & vbCrLf & "Exception Error:" & vbCrLf & ex.Message & vbCrLf & vbCrLf & _
            ex.GetType().ToString() & vbCrLf & vbCrLf & _
            "Stack Trace:" & vbCrLf & _
            ex.StackTrace

        Dim DisplayMessage As String = "An unhandled exception occurred. In order to improve this product please click OK to send the debug information to the support team." & vbCrLf & _
            vbCrLf & "SoftwareVersion: " & Version & vbCrLf & "System Info: " & SystemType & vbCrLf & vbCrLf & "Exception Error:" & vbCrLf & Left(ex.Message, 200)

        Return MessageBox.Show(DisplayMessage, _
           "Application Error", _
           MessageBoxButtons.OKCancel, _
           MessageBoxIcon.Stop)


    End Function

End Class ' ThreadExceptionHandler


Public Module Common

    Public RegistrationID As String = "UNREGISTERED"
    Public SkipField As String = "!! SKIP THIS FIELD !!"
    Public EncryptedUserid As String
    Public EncryptedPassword As String
    Public SystemKey As String = "LDKEIC84kdfmd493dldDDwsQLDDLEKK33kKDKE$mmdL#"
    Public UserKey As String
    Public Userid As Guid
    Public Username As String = ""
    Public ToggleLocked As Boolean = False 'used to indicate whether the password is displayed in the main grid or not
    Public CurrentlySelectedPasswordID As Guid
    Public CurrentlySelectedUserCategory As Guid
    Public FailedPasswordAttempts As Integer = 0
    Public RowCounter As Integer
    Public ConnectionString As String
    Public DatabasePath As String
    Public TestMode As Boolean = False
    Public ApplicationInstallPath As String
    Public BackgroundDataLoadingIgnoreEvents As Boolean = False
    Public RegisterLater As Boolean = False

    Dim TmpKey() As Byte
    Dim TmpIV() As Byte

    Private Cryptography As New CryptographyAES



    Public Function MyFormatDateForDatabase(ByVal DATEiN As Date) As String
        Return Format(DATEiN, "MM/dd/yyyy")
    End Function

    Public Function MyFormatDateForScreen(ByVal DATEiN As Date) As String
        Return Format(DATEiN, "dd/MM/yyyy")
    End Function



    Private Function OpenRS(ByVal Query As String, Optional ByVal ConnectionStringIn As String = "") As DataSet


        'screen movement
        SomethingChanged()

        Dim myConnection As Data.SqlServerCe.SqlCeConnection
        Dim myCommand As Data.SqlServerCe.SqlCeDataAdapter
        If Len(ConnectionStringIn) > 0 Then
            myConnection = New Data.SqlServerCe.SqlCeConnection(ConnectionStringIn)
        Else
            myConnection = New Data.SqlServerCe.SqlCeConnection(Common.ConnectionString)
        End If

        myConnection.Open()

        myCommand = New Data.SqlServerCe.SqlCeDataAdapter(Query, myConnection)
        Dim ds As DataSet = New DataSet()
        myCommand.Fill(ds)
        myConnection.Dispose()
        myCommand.Dispose()


        Return ds
    End Function

    Private Sub RunSQL(ByVal Query)

        'screen movement
        SomethingChanged()

        Dim myConnection As Data.SqlServerCe.SqlCeConnection
        Dim myCommand As Data.SqlServerCe.SqlCeCommand

        myConnection = New Data.SqlServerCe.SqlCeConnection(Common.ConnectionString)
        myConnection.Open()
        myCommand = New Data.SqlServerCe.SqlCeCommand
        myCommand.Connection = myConnection
        myCommand.CommandType = CommandType.Text
        myCommand.CommandText = Query
        myCommand.ExecuteNonQuery()
        myConnection.Dispose()
        myCommand.Dispose()

    End Sub

    Public Function CheckUserExists(ByVal Username) As Boolean
        Dim drUserCheck As DataSet
        drUserCheck = OpenRS("Select [Masterusername] from [user] where masterusername = '" & Encrypt(SystemKey, UCase(Username)) & "'")
        If drUserCheck.Tables(0).Rows.Count > 0 Then
            Return True
        Else
            Return False
        End If
        drUserCheck.Dispose()
    End Function


    Public Sub Sleep(ByVal Seconds As Integer)
        System.Threading.Thread.Sleep(Seconds * 1000)
    End Sub

   

    Public Function Login(ByVal Username, ByVal Password) As Boolean


        'make sure the database version is correct here....
        Call VerifyVersion()

        'Registry keys have a limit of 255 characters, so truncate here if necessary
        Dim RegistrySubKey As String = Left("FailedPasswords" & Common.Encrypt(Common.SystemKey, Username), 255)

        FailedPasswordAttempts = Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\Formition", RegistrySubKey, 0)
        If FailedPasswordAttempts > 3 Then

            Call Passwords.Message("Too many failed password attempts...", "You have tried " & FailedPasswordAttempts & " times to access your password, we will not lock you out but you just now had to wait " & FailedPasswordAttempts * 5 & " seconds...")
            'if you put a message in here, it does not keep any previous messages? fix this

            Sleep(FailedPasswordAttempts * 5)

        End If


        UserKey = Password & UCase(Username) & SystemKey

        Dim drUserCheck As DataSet
        drUserCheck = OpenRS("Select Userid,[Masterusername],[MasterPassword], PasswordReminder from [user] where masterusername = '" & Encrypt(SystemKey, UCase(Username)) & "' and MasterPassword='" & Encrypt(UserKey, Password) & "'")
        If drUserCheck.Tables(0).Rows.Count > 0 Then
            Userid = drUserCheck.Tables(0).Rows(0).Item("Userid")
            Common.Username = UCase(Username)
            'if there are no categories at all, setup a new one called "Web Passwords"
            Dim drCategoryCheck As DataSet
            drCategoryCheck = OpenRS("Select * from UserCategories where userid='" & Userid.ToString & "'")
            If drCategoryCheck.Tables(0).Rows.Count = 0 Then
                'create new category here
                Call DefaultCategoryCreate()
                Call Passwords.Message("New Category Created", "There were no categories, so one has been created by default for you called 'Web Passwords', you can rename this to something else if you prefer.", "Info")
            End If

            'choose the first category as the default one.
            drCategoryCheck = OpenRS("Select * from UserCategories where userid='" & Userid.ToString & "' order by Name asc")
            CurrentlySelectedUserCategory = drCategoryCheck.Tables(0).Rows(0).Item("UserCategoryID")

            'populate categories
            Common.PopulateCategories(CurrentlySelectedUserCategory)

            'reset the password failure count to speed up loggin in next time.

            Call Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\Formition", RegistrySubKey, 0)


            'set preferences
            Call PreferencesSetup(Userid)

            Passwords.txtSettingsUsername.Text = Username
            Passwords.txtSettingsPassword.PasswordChar = "*"
            Passwords.txtSettingsPassword.Text = Decrypt(UserKey, drUserCheck.Tables(0).Rows(0).Item("MasterPassword"))
            Passwords.txtSettingsPasswordConfirm.PasswordChar = "*"
            Passwords.txtSettingsPasswordConfirm.Text = Decrypt(UserKey, drUserCheck.Tables(0).Rows(0).Item("MasterPassword"))
            Passwords.txtSettingsPasswordReminder.Text = Decrypt(SystemKey, drUserCheck.Tables(0).Rows(0).Item("PasswordReminder"))
            Passwords.lblSettingsOriginalPasswordReminder.Text = Passwords.txtSettingsPasswordReminder.Text

            'Clear text search
            Passwords.txtSearch.Text = ""

            'remember last username
            Call Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\Formition", "LastLogonUserName", Username)

            'remember app path

            Call Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\Formition", "ApplicationRunningPath", Application.StartupPath.ToString)
            Call Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\Formition", "ApplicationConnectionString", Common.ConnectionString)
            Call Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\Formition", "ApplicationDatabasePath", Common.DatabasePath)

 
            Return True
        Else
            Call Microsoft.VisualBasic.Beep()
            Call Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\Formition", RegistrySubKey, FailedPasswordAttempts + 1)
            Return False
        End If

    End Function


    Public Function ValidateRegistration() As Boolean

        RegistrationID = Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\Formition", "RegistrationID", "")
        Dim validationstring As String = Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\Formition", "ValidationID", "")

        If Len(RegistrationID) = 36 Then
            If Encrypt(Common.SystemKey, RegistrationID) = validationstring Then                
                Passwords.lblRegistrationID.Text = RegistrationID
                Passwords.cmdAddRegistrationKey.Visible = False
                Passwords.lblRegistrationLink.Visible = False
                Return True

            Else
                Return False
            End If
        Else
            Return False
        End If

    End Function

    Public Sub DefaultCategoryCreate()
        RunSQL("Insert into UserCategories (Name, Userid, Deleted, Field1Name, Field2Name, Field3Name, Field4Name) values ('Web Passwords','" & Replace(Userid.ToString, "'", "''") & "',0,'Name','Website','Description','User name')")
      
    End Sub


    

    Public Function RegisterUser(ByVal Username, ByVal Password, ByVal PasswordReminder) As Boolean

        UserKey = Password & UCase(Username) & SystemKey

        'check that the username and password encrypted to not exceed 1000 characters each
        If Len(Encrypt(SystemKey, UCase(Username))) > 1000 Or Len(Encrypt(UserKey, Password)) > 1000 Then
            Call Passwords.Message("Error", "Your Username and Password when encrypted exceed 1000 characters it is too long to process.")
            Return False
        End If

        'we encrypt everything using the users own credentials and password, so that both are actually required do decrypt the users data

        Call RunSQL("Insert into [user] (MasterUsername, MasterPassword, CreationDate, PasswordReminder) values ('" & Encrypt(SystemKey, UCase(Username)) & "', '" & Encrypt(UserKey, Password) & "','" & GetDate() & "','" & Encrypt(SystemKey, PasswordReminder) & "')")


        Call Passwords.Message("Welcome", "You have now successfully created a new password safe, start by clicking the new password icon in the top left corner. If you want to add or remove categories click on the + symbol next to the categories.", "Info")
        Return True
    End Function


  
    Public Sub ResetUser(ByVal Userid, ByVal Username, ByVal Password, ByVal PasswordReminder)

        'here it gets tricky, all the current passwords are encrypted under the old password
        'we now have to check that the new userid and password is valid and then
        'update master username and password.

    End Sub

    Function Encrypt(ByVal Key As String, ByVal Text As String) As String

        Return Cryptography.Encrypt(Key, Text)

    End Function

    Function Decrypt(ByVal Key As String, ByVal Text As String) As String

        Return Cryptography.Decrypt(Key, Text)
    End Function

   

    Function SomethingChanged() As Boolean

        'reset the timeout facility
        Passwords.Timer1.Stop()
        Passwords.Timer1.Start()

    End Function

    Function EnforcePasswordLimit() As Boolean
        'has this user already got 10 passwords?
        Dim ds As DataSet = OpenRS("Select PasswordId from [password] where userid='" & Userid.ToString & "'")
        If ds.Tables(0).Rows.Count >= 15 Then
            Return True
        Else
            Return False
        End If
    End Function

    Sub NewPassword()

        If RegisterLater Then
            'they can have 15 passwords at most in the system.
            If EnforcePasswordLimit() Then
                Call Passwords.Message("Limit Reached", "There is a 15 password limit until you register this software, go to Advanced Settings > Registration to register!")
                Exit Sub
            End If
        End If

        If Passwords.cboCategory.Items.Count = 0 Then
            Call Passwords.SetupScreen("CategoryEditor")
            Passwords.Message("New Password Error", "Please create a category before creating new passwords, currently there are none. You can create a category here.")
            Exit Sub
        End If

        'setup password editor
        CurrentlySelectedPasswordID = Nothing
        Passwords.SetupScreen("Editor")
        Passwords.cboEditorCategory.SelectedValue = Passwords.cboCategory.SelectedValue
        Passwords.txtEditorName.Text = ""
        Passwords.txtEditorWebsite.Text = ""
        Passwords.txtEditorDescription.Text = ""
        Passwords.txtEditorUsername.Text = ""
        Passwords.txtEditorPassword.Text = ""
        Passwords.txtEditorConfirmPassword.Text = ""
        Passwords.SecurityControlPasswordEditor.SetLevel(0)
        Passwords.lblEditorCreatedDate.Text = ""
        Passwords.lblEditorLastModifiedDate.Text = ""

        'repopulate category listing (remove any "search results")
        Call PopulateCategories(Common.CurrentlySelectedUserCategory)

    End Sub

    Function GetDate() As String
        Return MyFormatDateForDatabase(Now.Date)
    End Function


    Function RandomChar() As String
        Dim TempChar
        Dim outChar As Integer = 0

        Do Until outChar > 0

            TempChar = System.Math.Round((Rnd() * (Second(Now) + 48)), 0) + 48

            'valid number
            If TempChar >= 48 And TempChar <= 57 Then
                outChar = TempChar
            ElseIf TempChar >= 65 And TempChar <= 122 Then
                If TempChar < 90 Or TempChar > 97 Then
                    'Valid character
                    outChar = TempChar
                Else
                    'junk character
                    outChar = 0
                End If
            Else
                'junk character
                outChar = 0
            End If

        Loop

        RandomChar = Chr(outChar)

    End Function

    Public Sub PopulateCategories(Optional ByVal DefaultGUID = "")

        'Prevent combobox from selecting data as it is loaded.
        BackgroundDataLoadingIgnoreEvents = True

        'if there are no categories at all, setup a new one called "Web Passwords"
        Dim drCategoryCheck As DataSet
        drCategoryCheck = OpenRS("Select UserCategoryID, Name from UserCategories where userid='" & Userid.ToString & "' order by Name asc")

        Passwords.cboCategory.DataSource = drCategoryCheck.Tables(0)
        Passwords.cboCategory.DisplayMember = "Name"
        Passwords.cboCategory.ValueMember = "UserCategoryID"

        Passwords.cboEditorCategory.DataSource = drCategoryCheck.Tables(0)
        Passwords.cboEditorCategory.DisplayMember = "Name"
        Passwords.cboEditorCategory.ValueMember = "UserCategoryID"


        If Not DefaultGUID Is Nothing Then
            Passwords.cboCategory.SelectedValue = DefaultGUID
            Passwords.cboEditorCategory.SelectedValue = DefaultGUID
        End If

        'Prevent combobox from selecting data as it is loaded.
        BackgroundDataLoadingIgnoreEvents = False

    End Sub

    Public Sub Search(ByVal SearchText As String, ByVal DisplayPassword As Boolean)

        Dim drPasswordCheck As DataSet
        drPasswordCheck = OpenRS("Select PasswordID, Name, Description, WebsiteAddress,Username, Password,CreatedDate,Strength,LastModifiedDate from Password where  Userid='" & Userid.ToString & "'")

        If drPasswordCheck.Tables(0).Rows.Count = 0 Then
            Call Passwords.Message("Search Results Error", "No passwords entries matched.")
        End If

        'Translate data into real fields
        Dim thisrow As DataRow
        For Each thisrow In drPasswordCheck.Tables(0).Rows
            thisrow.Item("Name") = Decrypt(UserKey, thisrow.Item("Name"))
            thisrow.Item("Description") = Decrypt(UserKey, thisrow.Item("Description"))
            thisrow.Item("WebsiteAddress") = Decrypt(UserKey, thisrow.Item("WebsiteAddress"))
            thisrow.Item("Username") = Decrypt(UserKey, thisrow.Item("Username"))
            thisrow.Item("Strength") = Decrypt(UserKey, thisrow.Item("Strength"))
            If DisplayPassword = True Then
                thisrow.Item("Password") = Decrypt(UserKey, thisrow.Item("Password"))
            Else
                thisrow.Item("Password") = "**********"
            End If

            drPasswordCheck.AcceptChanges()
        Next

        'now search the text for a match
        For Each thisrow In drPasswordCheck.Tables(0).Rows
            Dim keep As Boolean = False
            If InStr(thisrow.Item("Name"), SearchText, CompareMethod.Text) > 0 Then
                keep = True
            End If
            If InStr(thisrow.Item("WebsiteAddress"), SearchText, CompareMethod.Text) > 0 Then
                keep = True
            End If
            If InStr(thisrow.Item("Username"), SearchText, CompareMethod.Text) > 0 Then
                keep = True
            End If
            If InStr(thisrow.Item("Strength"), SearchText, CompareMethod.Text) > 0 Then
                keep = True
            End If
            If InStr(thisrow.Item("Password"), SearchText, CompareMethod.Text) > 0 Then
                keep = True
            End If

            If keep = False Then
                thisrow.Delete()
            End If
        Next

        'accept the deletions
        drPasswordCheck.AcceptChanges()

        'stop the grid from displaying the field names
        Passwords.DataGridPasswords.ColumnHeadersVisible = False

        Passwords.DataGridPasswords.DataSource = drPasswordCheck
        Passwords.DataGridPasswords.DataMember = drPasswordCheck.Tables(0).TableName
        'hide the password cell from the users.
        Passwords.DataGridPasswords.Columns(0).Visible = False

        'the category is now mixed, so represent this with the search results column

        'this will reset the categories (remove any unnessary existing search result fields")
        Call Common.PopulateCategories()

        Dim NewRow As DataRow = Passwords.cboCategory.DataSource.newrow
        NewRow.Item("UserCategoryID") = DBNull.Value
        NewRow.Item("Name") = "Search Results..."

        Passwords.cboCategory.DataSource.rows.add(NewRow)
        Passwords.cboCategory.DataSource.AcceptChanges()
        Passwords.cboCategory.SelectedIndex = Nothing
        Passwords.cboCategory.SelectedIndex = Passwords.cboCategory.Items.Count - 1

        'try to make the currently selected password the default selected on
        If Not CurrentlySelectedPasswordID = Nothing Then
            'try to re-select that password
            Try
                'this crashes when the password has been deleted
                Passwords.DataGridPasswords.Item(1, RowCounter).Selected = True
                Call Common.PasswordRowSelected()
            Catch ex As Exception
                'reset it to nothing
                Common.CurrentlySelectedPasswordID = Nothing
            End Try
        Else
            If drPasswordCheck.Tables(0).Rows.Count > 0 Then
                Passwords.DataGridPasswords.Item(1, 0).Selected = True
                Call Common.PasswordRowSelected()
            End If
        End If

    End Sub

    Public Sub PopulatePasswordList(ByVal CategoryId As Object, Optional ByVal DisplayPassword As Boolean = False)
        Dim drPasswordCheck As DataSet


        If Len(CategoryId.ToString) > 0 Then
            drPasswordCheck = OpenRS("Select PasswordID, Name,WebsiteAddress,Description,Username, Password,CreatedDate,Strength,LastModifiedDate from Password where UserCategoryId='" & CategoryId.ToString & "' and Userid='" & Userid.ToString & "'")
        Else

            Call Common.Search(Passwords.txtSearch.Text, ToggleLocked)
            Exit Sub
        End If


        If drPasswordCheck.Tables(0).Rows.Count = 0 Then
            drPasswordCheck = New DataSet("Empty Table")
            Dim EmptyPasswordTable As New DataTable("Empty Table")
            drPasswordCheck.Tables.Add(EmptyPasswordTable)
            Passwords.DataGridPasswords.DataSource = drPasswordCheck
            Passwords.DataGridPasswords.DataMember = drPasswordCheck.Tables(0).TableName
            Call PasswordRowSelected()
            Exit Sub
        End If


        Passwords.ToolStripComboBox1.Items.Clear()
        Passwords.ToolStripComboBox1.Items.Add("Toolbox Shortcuts >")
        Passwords.ToolStripComboBox1.SelectedIndex = 0
        Dim thisrow As DataRow
        For Each thisrow In drPasswordCheck.Tables(0).Rows
            thisrow.Item("Name") = Decrypt(UserKey, thisrow.Item("Name"))
            thisrow.Item("Description") = Decrypt(UserKey, thisrow.Item("Description"))
            thisrow.Item("WebsiteAddress") = Decrypt(UserKey, thisrow.Item("WebsiteAddress"))
            thisrow.Item("Username") = Decrypt(UserKey, thisrow.Item("Username"))
            thisrow.Item("Strength") = Decrypt(UserKey, thisrow.Item("Strength"))

            'bind the other taskbar menu
            Passwords.ToolStripComboBox1.Items.Add(thisrow.Item("Name"))
            Passwords.AddNewPasswordToolStripMenuItem.Enabled = True

            If DisplayPassword = True And thisrow.Item("PasswordID").ToString = Common.CurrentlySelectedPasswordID.ToString Then
                thisrow.Item("Password") = Decrypt(UserKey, thisrow.Item("Password"))
            Else
                thisrow.Item("Password") = "**********"
            End If

        Next

        drPasswordCheck.AcceptChanges()


        Common.SortTable(drPasswordCheck.Tables(0), "Name asc")
        
        'adjust category field names
        Dim ds As DataSet
        ds = CategorySearchByID(CategoryId)
        drPasswordCheck.Tables(0).Columns("Name").ColumnName = ds.Tables(0).Rows(0).Item("Field1Name")
        drPasswordCheck.Tables(0).Columns("Description").ColumnName = ds.Tables(0).Rows(0).Item("Field3Name")
        drPasswordCheck.Tables(0).Columns("WebsiteAddress").ColumnName = ds.Tables(0).Rows(0).Item("Field2Name")
        drPasswordCheck.Tables(0).Columns("Username").ColumnName = ds.Tables(0).Rows(0).Item("Field4Name")

        
        drPasswordCheck.AcceptChanges()

        'Allow us to see the category headers
        Passwords.DataGridPasswords.ColumnHeadersVisible = True

        Passwords.DataGridPasswords.DataSource = drPasswordCheck
        Passwords.DataGridPasswords.DataMember = drPasswordCheck.Tables(0).TableName
        'hide the password cell from the users.
        Passwords.DataGridPasswords.Columns(0).Visible = False


        


        'try to make the currently selected password the default selected on
        If Not CurrentlySelectedPasswordID = Nothing Then
            'try to re-select that password
            Try
                'this crashes when the password has been deleted
                Passwords.DataGridPasswords.Item(1, RowCounter).Selected = True
                Call Common.PasswordRowSelected()
            Catch ex As Exception
                'reset it to nothing
                Common.CurrentlySelectedPasswordID = Nothing
            End Try
        Else
            If drPasswordCheck.Tables(0).Rows.Count > 0 Then
                Passwords.DataGridPasswords.Item(1, 0).Selected = True
                Call Common.PasswordRowSelected()
            End If
        End If
    End Sub

    Public Function PasswordSearch(ByVal PasswordID As Object, ByVal Userid As String, ByVal Name As String, ByVal Description As String, ByVal WebsiteAddress As String, ByVal Username As String, ByVal Password As String, ByVal CreatedDate As String, ByVal UserCategoryID As String, ByVal Strength As String, ByVal LastModifiedDate As String) As DataSet

        Dim QB As New QueryBuilder
        QB.AddField("PasswordID", PasswordID, "String")
        QB.AddField("Userid", Userid, "String")
        QB.AddField("Name", Name, "String")
        QB.AddField("Description", Description, "nText")
        QB.AddField("WebsiteAddress", WebsiteAddress, "nText")
        QB.AddField("Username", Username, "String")
        QB.AddField("Password", Password, "String")
        QB.AddField("CreatedDate", CreatedDate, "Date")
        QB.AddField("UserCategoryID", UserCategoryID, "String")
        QB.AddField("Strength", Strength, "String")
        QB.AddField("LastModifiedDate", LastModifiedDate, "Date")

        Return OpenRS(QB.GetSearchString("Password", "*"))

    End Function

    Public Sub PasswordEdit(ByVal PasswordID, ByVal Userid, ByVal Name, ByVal Description, ByVal WebsiteAddress, ByVal UsernameIn, ByVal Password, ByVal CreatedDate, ByVal UserCategoryID, ByVal Strength, ByVal LastModifiedDate)

        Dim QB As New QueryBuilder
        'QB.AddField("PasswordID", PasswordID, "String")
        QB.AddField("Userid", Userid, "String")
        QB.AddField("Name", Common.Encrypt(Common.UserKey, Name), "String")
        QB.AddField("Description", Common.Encrypt(Common.UserKey, Description), "nText")
        QB.AddField("WebsiteAddress", Common.Encrypt(Common.UserKey, WebsiteAddress), "nText")

        QB.AddField("Username", Common.Encrypt(Common.UserKey, UsernameIn), "String")
        QB.AddField("Password", Common.Encrypt(Common.UserKey, Password), "String")
        QB.AddField("CreatedDate", CreatedDate, "Date")
        QB.AddField("UserCategoryID", UserCategoryID, "String")
        QB.AddField("Strength", Common.Encrypt(Common.UserKey, Strength), "String")
        QB.AddField("LastModifiedDate", LastModifiedDate, "Date")

        If PasswordID.ToString <> SkipField Then
            Call RunSQL(QB.GetUpdateString("Password", "Where PasswordID='" & PasswordID.ToString & "'"))
        Else
            Call RunSQL(QB.GetInsertString("Password"))
        End If


    End Sub


    Sub PasswordSelected(ByVal PasswordID)

        Passwords.SetupScreen("Editor")

        Dim DsPassword As DataSet
        DsPassword = OpenRS("Select * from Password where passwordid='" & PasswordID.ToString & "'")
        If DsPassword.Tables(0).Rows.Count = 0 Then
            Call Passwords.Message("Error", "The selected password no longer exists in the database.")
            Call Passwords.SetupScreen("MainScreen")
            Exit Sub
        End If

        Common.CurrentlySelectedPasswordID = DsPassword.Tables(0).Rows(0).Item("PasswordID")
        Passwords.txtEditorName.Text = Decrypt(UserKey, DsPassword.Tables(0).Rows(0).Item("Name").ToString)
        Passwords.txtEditorDescription.Text = Decrypt(UserKey, DsPassword.Tables(0).Rows(0).Item("Description").ToString)
        Passwords.txtEditorWebsite.Text = Decrypt(UserKey, DsPassword.Tables(0).Rows(0).Item("WebsiteAddress").ToString)
        Passwords.txtEditorUsername.Text = Decrypt(UserKey, DsPassword.Tables(0).Rows(0).Item("Username").ToString)
        Passwords.txtEditorConfirmPassword.Text = Decrypt(UserKey, DsPassword.Tables(0).Rows(0).Item("Password").ToString)
        Passwords.txtEditorPassword.Text = Decrypt(UserKey, DsPassword.Tables(0).Rows(0).Item("Password").ToString)

        Passwords.cboEditorCategory.SelectedValue = DsPassword.Tables(0).Rows(0).Item("UserCategoryID").ToString

        Passwords.SecurityControlPasswordEditor.SetLevel(Common.CheckPasswordStrength(Decrypt(UserKey, DsPassword.Tables(0).Rows(0).Item("Password").ToString)))

        Passwords.lblEditorCreatedDate.Text = "Created on " & MyFormatDateForScreen(DsPassword.Tables(0).Rows(0).Item("CreatedDate").ToString)
        Passwords.lblEditorLastModifiedDate.Text = "Last Modified on " & MyFormatDateForScreen(DsPassword.Tables(0).Rows(0).Item("LastModifiedDate").ToString)

    End Sub

    Function CheckPasswordStrength(ByVal Password As String, Optional ByVal UsernameIn As String = "") As String

        Dim Score As Integer

        If Len(Password) <= 3 Then
            Score = -3
        ElseIf Len(Password) = 4 Then
            Score = -1
        ElseIf Len(Password) = 5 Then
            Score = 1
        ElseIf Len(Password) = 6 Then
            Score = 2
        ElseIf Len(Password) = 7 Then
            Score = 3
        ElseIf Len(Password) = 8 Then
            Score = 3
        ElseIf Len(Password) = 9 Then
            Score = 4
        ElseIf Len(Password) = 10 Then
            Score = 4
        ElseIf Len(Password) >= 11 Then
            Score = 5
        End If


        Dim containsNumbers As Boolean = False
        Dim containsUppercase As Boolean = False
        Dim containsLowercase As Boolean = False


        Dim x As Char
        For Each x In Password.ToString
            If IsNumeric(x) Then
                containsNumbers = True
            End If
            If UCase(x) <> x Then
                containsUppercase = True
            End If
            If LCase(x) <> x Then
                containsLowercase = True
            End If
        Next

        If containsNumbers And containsUppercase And containsLowercase Then
            Score = Score + 3
        ElseIf containsNumbers And (containsUppercase Or containsLowercase) Then
            Score = Score + 1
        ElseIf containsUppercase And (containsNumbers Or containsLowercase) Then
            Score = Score + 1
        End If

        If Len(UsernameIn) > 0 Then
            If InStr(Password, UsernameIn, CompareMethod.Text) > 0 Then
                Score = Score - 4
            End If
        End If

        If InStr(Password, "123", CompareMethod.Text) > 0 Then
            Score = Score - 1
        End If
        If InStr(Password, "2010", CompareMethod.Text) > 0 Then
            Score = Score - 1
        End If
        If InStr(Password, "2011", CompareMethod.Text) > 0 Then
            Score = Score - 1
        End If
        If InStr(Password, "2012", CompareMethod.Text) > 0 Then
            Score = Score - 1
        End If
        If InStr(Password, "2013", CompareMethod.Text) > 0 Then
            Score = Score - 1
        End If

        Return Score
    End Function

    Function ScoreToText(ByVal Score) As String

        If Score <= 0 Then
            Return "Poor"
        End If
        Select Case Score
            Case 1 : Return "Poor"
            Case 2 : Return "Poor"
            Case 3 : Return "Medium"
            Case 4 : Return "Medium"
            Case 5 : Return "Medium"
            Case 6 : Return "Strong"
            Case Else : Return "Very Strong"
        End Select
    End Function

    Sub DeletePassword(ByVal PasswordID)
        Dim DeleteRow As String
        DeleteRow = MsgBox("Are you sure you want to delete this record?", MsgBoxStyle.OkCancel, "Formition Password Safe")

        If DeleteRow = 1 Then

            'delete the record
            RunSQL("Delete from Password where Passwordid='" & PasswordID.ToString & "'")

            'redisplay the category list
            Call Common.PopulatePasswordList(Passwords.cboEditorCategory.SelectedValue, Common.ToggleLocked)

            Toolbox.Visible = False

        End If



    End Sub

    Public Sub DeleteTestUser(ByVal Userid)
        Call RunSQL("Delete from [User] where Userid='" & Userid.ToString & "'")
        Call RunSQL("Delete from [UserCategories] where Userid='" & Userid.ToString & "'")
        Call RunSQL("Delete from [Password] where Userid='" & Userid.ToString & "'")
        Call RunSQL("Delete from [Settings] where Userid='" & Userid.ToString & "'")
    End Sub

    Public Sub PreferencesSave()



        '------------------------------------
        ' CHANGE MASTER USERNAME AND PASSWORD
        '------------------------------------

        If Len(Passwords.txtSettingsUsername.Text) = 0 Or Len(Passwords.txtSettingsPassword.Text) = 0 Then
            Call Passwords.Message("Settings Save", "The Master Username and Master Password cannot be blank.")
            Exit Sub
        End If

        If Not Passwords.txtSettingsPassword.Text = Passwords.txtSettingsPasswordConfirm.Text Then
            Call Passwords.Message("Settings Save", "New passwords do not match.")
            Exit Sub
        End If

        Dim UserNameChange As Boolean = False
        Dim PasswordChange As Boolean = False

        If UCase(Common.Username) <> UCase(Passwords.txtSettingsUsername.Text) Then
            If Common.CheckUserExists(Passwords.txtSettingsUsername.Text) Then
                Call Passwords.Message("Preferences Save", "The username you have selected already exists, you cannot use this userid.")
                Exit Sub
            End If
            UserNameChange = True
        End If

        'try logging in...(to test if password has changed!)
        If LoginTest(Common.Username, Passwords.txtSettingsPassword.Text) = False Then
            PasswordChange = True
        End If


        If UserNameChange Or PasswordChange Then

            If Passwords.chkMasterPasswordChange.Checked = False Then
                Call Passwords.Message("Preference Save", "If you wish to change your master username or password you must check the box on this screen to ensure you understand the consequences of forgetting either.")
                Exit Sub
            End If

            'Make user confirm this change
            Dim ConfirmChange As String = 0
            If UserNameChange And PasswordChange Then
                ConfirmChange = MsgBox("Are you sure you want to change your master username and master password?", MsgBoxStyle.OkCancel, "Formition Password Safe")
                If ConfirmChange <> 1 Then
                    Exit Sub
                End If
            ElseIf UserNameChange Then
                ConfirmChange = MsgBox("Are you sure you want to change your master username?", MsgBoxStyle.OkCancel, "Formition Password Safe")
                If ConfirmChange <> 1 Then
                    Exit Sub
                End If
            ElseIf PasswordChange Then
                ConfirmChange = MsgBox("Are you sure you want to change your master password?", MsgBoxStyle.OkCancel, "Formition Password Safe")
                If ConfirmChange <> 1 Then
                    Exit Sub
                End If
            End If

            'We need to retreive EVERY PASSWORD and decryt and then encrypt using the new key

            Dim drPasswordCheck2 As DataSet
            drPasswordCheck2 = OpenRS("Select * from Password where Userid='" & Userid.ToString & "'")

            Dim thisrow As DataRow
            For Each thisrow In drPasswordCheck2.Tables(0).Rows
                thisrow.Item("Name") = Decrypt(UserKey, thisrow.Item("Name"))
                thisrow.Item("WebsiteAddress") = Decrypt(UserKey, thisrow.Item("WebsiteAddress"))
                thisrow.Item("Description") = Decrypt(UserKey, thisrow.Item("Description"))
                thisrow.Item("Username") = Decrypt(UserKey, thisrow.Item("Username"))
                thisrow.Item("Strength") = Decrypt(UserKey, thisrow.Item("Strength"))
                'always unencrypt the password also
                thisrow.Item("Password") = Decrypt(UserKey, thisrow.Item("Password"))
            Next

            drPasswordCheck2.AcceptChanges()


            'set the new key, save all the passwords and then the username and password
            UserKey = Passwords.txtSettingsPassword.Text & UCase(Passwords.txtSettingsUsername.Text) & SystemKey

            'reset Master Username, Password and Password Hint
            Call RunSQL("Update [user]  set MasterUsername='" & Encrypt(SystemKey, UCase(Passwords.txtSettingsUsername.Text)) & "', MasterPassword='" & Encrypt(UserKey, Passwords.txtSettingsPassword.Text) & "' WHERE [USERID]='" & Common.Userid.ToString & "'")

            For Each thisrow In drPasswordCheck2.Tables(0).Rows
                'Update the passwords with the new encryption key
                'save password row re-encrypted
                Common.PasswordEdit(thisrow.Item("PasswordID").ToString, Common.Userid.ToString, thisrow.Item("Name"), thisrow.Item("Description"), thisrow.Item("WebsiteAddress"), thisrow.Item("Username"), thisrow.Item("Password"), Common.SkipField, Common.SkipField, thisrow.Item("Strength"), Common.SkipField)
            Next


            'system should be fully functional now.
            Call Passwords.Message("Preferences Save", "Master Username and Passwords and all data has been updated with the new combination.", "Info")

            Call Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\Formition", "LastLogonUserName", Passwords.txtSettingsUsername.Text)

        End If


        'Save the users password reminder
        If Passwords.lblSettingsOriginalPasswordReminder.Text <> Passwords.txtSettingsPasswordReminder.Text Then
            'update password reminder
            Call RunSQL("Update [user]  set PasswordReminder='" & Encrypt(SystemKey, Passwords.txtSettingsPasswordReminder.Text) & "' WHERE [USERID]='" & Common.Userid.ToString & "'")
            Passwords.lblSettingsOriginalPasswordReminder.Text = Passwords.txtSettingsPasswordReminder.Text
        End If

        '------------------------------------
        ' Basic Settings
        '------------------------------------


        Call UpdateBasicPreferences()

        Call Passwords.SetupScreen("MainScreen")
        Call Passwords.Status("Settings saved successfully.")
    End Sub

    Public Sub LogOff()

        'Important Settings
        Common.Userid = Nothing
        Common.Username = Nothing
        Common.UserKey = Nothing

        'Basic Preferences
        Passwords.chkBoxTips.Checked = False
        Passwords.ChkBoxAutoLockMinimise.Checked = True
        Passwords.ChkBoxAutoLockTimeout.Checked = True

        Call Passwords.SetupScreen("Login")
    End Sub

    Public Sub UpdateBasicPreferences()
        Dim AutotimeOut As Integer = 0
        Dim TimeoutOnMinimise As Integer = 0
        Dim HideTips As Integer = 0

        If Passwords.ChkBoxAutoLockTimeout.Checked Then
            AutotimeOut = 1
        End If

        If Passwords.ChkBoxAutoLockMinimise.Checked Then
            TimeoutOnMinimise = 1
        End If

        If Passwords.chkBoxTips.Checked Then
            HideTips = 1
        End If

        Call RunSQL("Update [Settings] set AutoTimeout=" & AutotimeOut & ", TimeoutOnMinimise=" & TimeoutOnMinimise & ",IgnoreTips=" & HideTips & " where userid='" & Userid.ToString & "'")

    End Sub

    Public Function LoginTest(ByVal Username, ByVal Password) As Boolean

        Dim drUserCheck As DataSet
        drUserCheck = OpenRS("Select Userid,[Masterusername],[MasterPassword], PasswordReminder from [user] where masterusername = '" & Encrypt(SystemKey, UCase(Username)) & "' and MasterPassword='" & Encrypt(UserKey, Password) & "'")
        If drUserCheck.Tables(0).Rows.Count > 0 Then
            Return True
        Else
            Return False
        End If
    End Function


    Public Sub PreferenceDefaults(ByVal Userid As Object)
        Call RunSQL("Delete from [Settings] where Userid='" & Userid.ToString & "'")
        Call RunSQL("Insert into [Settings] (Userid, AutoTimeout, TimeoutOnMinimise,IgnoreTips) values ('" & Userid.ToString & "',1,0,0)")
    End Sub

    Public Sub PreferencesSetup(ByVal Userid)
        Dim DsPreferences As DataSet
        DsPreferences = OpenRS("Select * from [Settings] where userid = '" & Userid.ToString & "'")
        If DsPreferences.Tables(0).Rows.Count = 0 Then
            'hmm no preferences, create new ones.
            Call PreferenceDefaults(Userid)
            DsPreferences = OpenRS("Select * from [Settings] where userid = '" & Userid.ToString & "'")
        End If

        'if still no preferences default
        If DsPreferences.Tables(0).Rows.Count = 0 Then
            'default
            Passwords.ChkBoxAutoLockTimeout.Checked = True
            Passwords.ChkBoxAutoLockMinimise.Checked = False
            Passwords.chkBoxTips.Checked = False
        Else
            Passwords.ChkBoxAutoLockTimeout.Checked = DsPreferences.Tables(0).Rows(0).Item("AutoTimeout")
            Passwords.ChkBoxAutoLockMinimise.Checked = DsPreferences.Tables(0).Rows(0).Item("TimeoutOnMinimise")
            Passwords.chkBoxTips.Checked = DsPreferences.Tables(0).Rows(0).Item("IgnoreTips")
        End If

    End Sub

    Public Sub CategoryEditorLoad(Optional ByVal ReturnToPasswordEditor As Boolean = False)


        Passwords.chkCategoryEditorReturnToPasswordEditor.Checked = ReturnToPasswordEditor
        Passwords.chkCategoryEditorShowAdvancedOptions.Visible = False

        Call Passwords.SetupScreen("CategoryEditor")

        'load category editor category list
        Call RefreshCategoryEditorCategoryList()


    End Sub

    Public Sub RefreshCategoryEditorCategoryList()
        'if there are no categories at all, setup a new one called "Web Passwords"
        Dim drCategoryCheck As DataSet
        drCategoryCheck = OpenRS("Select UserCategoryID, Name from UserCategories where userid='" & Userid.ToString & "'")

        Passwords.cboCategoryEditorCategory.DataSource = drCategoryCheck.Tables(0)
        Passwords.cboCategoryEditorCategory.DisplayMember = "Name"
        Passwords.cboCategoryEditorCategory.ValueMember = "UserCategoryID"

        
        Passwords.cboCategoryEditorCategory.Visible = True
        Passwords.txtCategoryEditorCategoryName.Visible = False
        Passwords.txtField1Name.Visible = False
        Passwords.txtField2Name.Visible = False
        Passwords.txtField3Name.Visible = False
        Passwords.txtField4Name.Visible = False
        Passwords.cmdCategoryEditorSave.Visible = False

        Passwords.chkCategoryEditorShowAdvancedOptions.Visible = False

        Passwords.lblCategoryName.Visible = False
        Passwords.lblField1Text.Visible = False
        Passwords.lblField2Text.Visible = False
        Passwords.lblField3Text.Visible = False
        Passwords.lblField4Text.Visible = False

        drCategoryCheck = Nothing

    End Sub

    Public Function CategorySearchByID(ByVal CategoryId) As DataSet
        Dim ds As DataSet
        ds = OpenRS("Select * from UserCategories where UserCategoryId = '" & CategoryId.ToString & "'")
        Return ds
    End Function


    Public Sub CategoryEdit(ByVal UserCategoryID, ByVal Name, ByVal Deleted, ByVal Userid, ByVal Field1Name, ByVal Field2Name, ByVal Field3Name, ByVal Field4Name)

        Dim QB As New QueryBuilder
        QB.AddField("Userid", Userid.ToString, "String")
        QB.AddField("Name", Name, "String")
        QB.AddField("Deleted", Deleted, "Integer")
        QB.AddField("Field1Name", Field1Name, "String")
        QB.AddField("Field2Name", Field2Name, "String")
        QB.AddField("Field3Name", Field3Name, "String")
        QB.AddField("Field4Name", Field4Name, "String")

        If UserCategoryID.ToString <> SkipField Then
            Call RunSQL(QB.GetUpdateString("UserCategories", " Where UserCategoryID='" & UserCategoryID.ToString & "'"))
            Call Passwords.Message("Rename category", "Category renamed.", "Info")
        Else
            Call RunSQL(QB.GetInsertString("UserCategories"))
            Call Passwords.Message("Create new category", "New category created.", "Info")
        End If


    End Sub

    Public Sub CategoryDelete(ByVal UserCategoryID)
        Call RunSQL("Delete from Password where UserCategoryID='" & UserCategoryID.ToString & "'")
        Call RunSQL("Delete from [UserCategories] where UserCategoryID='" & UserCategoryID.ToString & "'")
        Call Passwords.Message("Delete category", "Category deleted successfully and all associated passwords deleted successfully.", "Info")
    End Sub


    Public Sub CopyPasswordtoClipboard(ByVal PasswordID)

        If Len(PasswordID.ToString) = 0 Then
            Call Passwords.Message("Error copying to clipboard", "Please select a password first.")
            Exit Sub
        End If

        If PasswordID <> Nothing Then
            Dim dsPassword As New DataSet
            dsPassword = OpenRS("Select Password from Password where Passwordid='" & PasswordID.ToString & "'")
            If dsPassword.Tables(0).Rows.Count = 0 Then
                Call Passwords.Message("Error copying to clipboard", "The selected password entry was not found in the current database.")
                Exit Sub
            End If

            Clipboard.Clear()
            If Len(dsPassword.Tables(0).Rows(0).Item("Password")) > 0 Then
                Dim tmppass As String = Decrypt(Common.UserKey, dsPassword.Tables(0).Rows(0).Item("Password"))

                If Len(tmppass) > 0 Then
                    'try this twice if it fails
                    Try
                        Clipboard.SetText(tmppass)
                    Catch ex As Exception
                        Try
                            Clipboard.SetText(tmppass)
                        Catch ex2 As Exception
                            Call Passwords.Message("Copy Password", "Copying password to clipboard failed - please try again")
                            Exit Sub
                        End Try
                    End Try
                End If
            End If

            Call Passwords.Status("Password has been copied to clipboard successfully.")

        End If
    End Sub


    Public Sub CopyUseridToClipBoard(ByVal PasswordId)
        If PasswordId <> Nothing Then
            'Call MsgBox(Me.DataGridPasswords.SelectedRows.Item(0).Cells(3).Value.ToString)
            Clipboard.Clear()
            If Len(Passwords.DataGridPasswords.SelectedRows.Item(0).Cells(4).Value.ToString) > 0 Then
                If Len(Passwords.DataGridPasswords.SelectedRows.Item(0).Cells(4).Value.ToString) > 0 Then
                    Try
                        Clipboard.SetText(Passwords.DataGridPasswords.SelectedRows.Item(0).Cells(4).Value.ToString)
                    Catch ex As Exception
                        Try
                            Clipboard.SetText(Passwords.DataGridPasswords.SelectedRows.Item(0).Cells(4).Value.ToString)
                        Catch ex2 As Exception
                            Call Passwords.Message("Copy Userid", "Copying Userid to clipboard failed - please try again")
                        End Try

                    End Try

                End If
            End If

            Call Passwords.Status("Userid has been copied to clipboard successfully.")
        Else
            Call Passwords.Message("Error copying to clipboard", "Please select a password entry before selecting this option.")
        End If
    End Sub


    Function DoubleQuote() As String
        Return Left("""", 1)
    End Function

    Public Sub LaunchInBrowser(ByVal PasswordID)

        If PasswordID <> Nothing Then

            Dim dsPassword As New DataSet
            dsPassword = OpenRS("Select WebsiteAddress from Password where Passwordid='" & PasswordID.ToString & "'")
            If dsPassword.Tables(0).Rows.Count = 0 Then
                Call Passwords.Message("Error launching this website", "The selected password entry was not found in the current database.")
                Exit Sub
            End If

            Dim CurrentLink As String = Decrypt(UserKey, dsPassword.Tables(0).Rows(0).Item("WebsiteAddress"))


            Dim IfNeeded As String = ""
            If InStr(CurrentLink, "http://") = 0 And InStr(CurrentLink, "ftp://") = 0 And InStr(CurrentLink, "https://") = 0 Then
                IfNeeded = "http://"
            End If

            CurrentLink = Environ("windir") & "\explorer.exe " & Left("""", 1) & IfNeeded & CurrentLink & Left("""", 1)
            Dim rc As Integer
            If Len(CurrentLink) > 7 Then
                rc = Shell(CurrentLink, vbNormalFocus)
                Call Passwords.Status("Website has been launched in browser.")
            Else
                Call Passwords.Message("Launching in browser", "Web URL was invalid")
            End If


        Else
            Call Passwords.Message("Launching in browser", "Please select a password entry before selecting this option.")
        End If
    End Sub

    Public Sub PasswordRowSelected(Optional ByVal ChangeSelection As Boolean = True)


        Dim Value As Boolean = False


        If Passwords.DataGridPasswords.RowCount > 0 Then

            Try


                If Len(Passwords.DataGridPasswords.SelectedRows.Item(0).Cells(0).Value.ToString) > 0 Then

                    'if the calling function tells us this is a selection change by the user, then 
                    'record the new selected password.
                    If ChangeSelection Then
                        CurrentlySelectedPasswordID = Passwords.DataGridPasswords.SelectedRows.Item(0).Cells(0).Value
                        RowCounter = Passwords.DataGridPasswords.SelectedCells(0).RowIndex
                    End If

                    Passwords.cmdCopyPassword.Enabled = True
                    Passwords.cmdCopyUserid.Enabled = True
                    Passwords.cmdLockPasswords.Enabled = True
                    Passwords.cmdDelete.Enabled = True
                    Passwords.cmdLaunchWeblink.Enabled = True
                    Passwords.ContextMenuStrip1.Enabled = True
                    Passwords.cmdOpenToolbox.Enabled = True

                    Value = True
                    Passwords.ToolStripMenuItem_Edit.Enabled = Value
                    Passwords.ToolStripMenuItem_Delete.Enabled = Value
                    Passwords.ToolStripMenuItem_CopyPassword.Enabled = Value
                    Passwords.ToolStripMenuItem_CopyUserid.Enabled = Value
                    Passwords.ShowUsernameToolStripMenuItem.Enabled = Value
                    Passwords.LaunchInBrowserToolStripMenuItem.Enabled = Value
                    Passwords.LaunchToolboxToolStripMenuItem.Enabled = Value

                    Call Passwords.Status(Passwords.DataGridPasswords.SelectedRows.Item(0).Cells(1).Value.ToString)

                    'now change toolbox but don't display it or hide toolbox form.
                    LaunchToolbox(False, False)
                    Exit Sub
                End If

            Catch ex As Exception
                'haven't found a way to detect an empty grid yet, will work out later.
            End Try
        End If


        Passwords.cmdCopyPassword.Enabled = False
        Passwords.cmdCopyUserid.Enabled = False

        Passwords.cmdLockPasswords.Enabled = False
        Passwords.cmdDelete.Enabled = False
        Passwords.cmdLaunchWeblink.Enabled = False
        Passwords.cmdOpenToolbox.Enabled = False
        CurrentlySelectedPasswordID = Nothing

        'Passwords.ContextMenuStrip1.Enabled = False

        Value = False
        Passwords.ToolStripMenuItem_Edit.Enabled = Value
        Passwords.ToolStripMenuItem_Delete.Enabled = Value
        Passwords.ToolStripMenuItem_CopyPassword.Enabled = Value
        Passwords.ToolStripMenuItem_CopyUserid.Enabled = Value
        Passwords.ShowUsernameToolStripMenuItem.Enabled = Value
        Passwords.LaunchInBrowserToolStripMenuItem.Enabled = Value
        Passwords.LaunchToolboxToolStripMenuItem.Enabled = Value

    End Sub

    Public Sub ExitScreenCode(ByVal ScreenName)
        Call Passwords.SetupScreen("MainScreen")
    End Sub

    Public Sub PasswordReminder(ByVal Username)


        'Registry keys have a limit of 255 characters, so truncate here if necessary
        Dim RegistrySubKey As String = Left("FailedPasswords" & Common.Encrypt(Common.SystemKey, Username), 255)

        Dim drUserCheck As DataSet
        drUserCheck = OpenRS("Select Userid,[Masterusername],PasswordReminder from [user] where masterusername = '" & Encrypt(SystemKey, UCase(Username)) & "'")
        If drUserCheck.Tables(0).Rows.Count > 0 Then
            Call Passwords.Message("Forgotten password reminder", Decrypt(SystemKey, drUserCheck.Tables(0).Rows(0).Item("PasswordReminder")), "Info")
        Else
            Call Passwords.Message("Forgotten password reminder", "Username not found, try another.")
        End If
    End Sub

    Public Sub LaunchToFormition()

        Dim CurrentLink As String = Environ("windir") & "\explorer.exe " & Common.DoubleQuote & "http://www.formition.com/default.aspx" & Common.DoubleQuote
        Dim rc As Integer
        rc = MsgBox("Would you like to go to the Formition.com website?", MsgBoxStyle.OkCancel)
        If rc = 1 Then
            rc = Shell(CurrentLink, vbNormalFocus)
            Call Passwords.Status("web browsewr for Formition.com opened")
        End If

    End Sub

    Public Sub Backup(ByVal Filename As String, Optional ByVal Silent As Boolean = False)


        Toolbox.Close()

        Passwords.Timer1.Enabled = False

        Passwords.GroupBoxSettings.Enabled = False
        'Passwords.Enabled = False


        Try

            'first step is to wait 10 seconds to ensure database is backed up.
            'Call Sleep(10)

            FileIO.FileSystem.CopyFile(Common.DatabasePath & "PasswordCache.sdf", Filename, True)


            'check databae integrity
            Dim results As String = DatabaseIntegrityTest(Filename)
            If Len(results) > 0 Then
                If Silent = False Then
                    Call Passwords.Message("Backup Failed", "The backup failed, the file created did not pass the database integrity test. It failed at this test : " & results)
                    Exit Sub
                Else
                    'this needs to go back to the calling function that performed the backup
                    Dim ex33 As New Exception("The pre restore database backup failed, the file created did not pass the database integrity test. It failed at this test : " & results)
                    Throw ex33
                End If

            End If

            If Silent = False Then Call Passwords.Message("Backup Database", "Backup Finished Successfully.", "Info")

        Catch ex As Exception
            If Silent = False Then Call Passwords.Message("Backup Database", "Backup Failed : " & ex.Message)
        End Try

        'Passwords.Enabled = True
        Passwords.GroupBoxSettings.Enabled = True


        Passwords.Timer1.Enabled = True
    End Sub


    Public Function DatabaseIntegrityTest(ByVal PathAndFileNameofDB As String) As String
        Dim ThisConnectionString = "Data Source=" & PathAndFileNameofDB & ";"

        Dim testno As String = "Test 0 : Unknown"

        Try
            testno = "Test 1 : Password Table"
            Dim tmprs As DataSet
            tmprs = OpenRS("Select * from [Password]", ThisConnectionString)

            testno = "Test 2 : Settings Table"
            tmprs = OpenRS("Select * from [Settings]", ThisConnectionString)

            testno = "Test 3 : System Table"
            tmprs = OpenRS("Select * from [System]", ThisConnectionString)

            testno = "Test 4 : User Table"
            tmprs = OpenRS("Select * from [User]", ThisConnectionString)

            testno = "Test 5 : UserCategories Table"
            tmprs = OpenRS("Select * from [UserCategories]", ThisConnectionString)

        Catch ex As Exception

            Return "Database is corrupt, failed at " & testno

        End Try

        Return ""

    End Function

    Public Sub Restore(ByVal Filename)

        Toolbox.Close()

        'before we do anything, lets make sure this database is valid

        Dim Results As String = DatabaseIntegrityTest(Filename)
        If Len(Results) > 0 Then
            Call Passwords.Message("Restore Database Corrupted", "After performing a test on the database you wish to restore it appears that this file is not a valid database or is corrupted. The restore did not start. The database test that failed was : " & Results, "Warning")
            Exit Sub
        End If

        Passwords.Timer1.Enabled = False

        'Passwords.Enabled = False
        Passwords.GroupBoxSettings.Enabled = False

        Dim BackupFileName As String = Common.DatabasePath & "\PasswordCache.tmp~" & Now.Ticks

        Try

            'backup the database to a temp area

            Backup(BackupFileName, True)

            If FileIO.FileSystem.FileExists(Filename) Then
                FileIO.FileSystem.CopyFile(Filename, Common.DatabasePath & "PasswordCache.sdf", True)
            End If


            FileIO.FileSystem.DeleteFile(BackupFileName)


            Call Common.VerifyVersion()

            'now go to the login screen
            Common.LogOff()

            Call Passwords.Message("Restore Database", "Restore finished successfully. You will need to log in again to verify yourself", "Info")

        Catch ex As Exception

            Call Passwords.Message("Restore Database Failed!", "Restore failed : " & ex.Message)
            Call Passwords.Message("Restore Database Failed!", "A backup of your database was taken before the restore began and can be found here : " & BackupFileName)

        End Try



        'Passwords.Enabled = True
        Passwords.GroupBoxSettings.Enabled = True

        Passwords.Timer1.Enabled = True
    End Sub

    Public Sub VerifyVersion()
        'check the database version
        If DatabaseVersion() <> Passwords.VersionPasswordSafe Then
            Dim result As String = MsgBox("The database you are using is from is from a future version of this program (v" & DatabaseVersion() & ". Forwards compatibility is not possible, do you want to check to see if there is a later version of this software?", MsgBoxStyle.OkCancel, "Formition Password Safe")
            If result = 1 Then
                Call Passwords.UpgradeSoftwareVersion()
                Passwords.Close()
            Else
                Passwords.Close()
            End If
        End If
    End Sub

    Public Function DatabaseVersion() As Integer


        Dim rs As New DataSet
        rs = OpenRS("Select * from [System]")
        If rs.Tables(0).Rows.Count > 0 Then
            Return rs.Tables(0).Rows(0).Item("DatabaseVersion")
        End If

    End Function

    Public Sub LaunchToolbox(Optional ByVal DisplayPassword As Boolean = False, Optional ByVal ChangeVisibilityState As Boolean = True)

        Dim PasswordId As Object = Common.CurrentlySelectedPasswordID

        'only change this to be visible if started from the main menu button.
        If ChangeVisibilityState Then
            Dim newco As New System.Drawing.Point(0, 0)
            Toolbox.Location = newco
            Toolbox.Enabled = True
            Toolbox.Visible = True
            Toolbox.BringToFront()
        End If

        If Len(PasswordId.ToString) = 0 Then
            Call Passwords.Message("Error launching Toolbox", "Please select a password first.")
            Exit Sub
        End If

        If PasswordId <> Nothing Then
            Dim dsPassword As New DataSet
            dsPassword = OpenRS("Select * from Password where Passwordid='" & PasswordId.ToString & "'")
            If dsPassword.Tables(0).Rows.Count = 0 Then
                Call Passwords.Message("Error launching Toolbox", "The selected password entry was not found in the current database.")
                Exit Sub
            End If


            If dsPassword.Tables(0).Rows.Count > 0 Then

                Toolbox.lblPasswordID.Text = CurrentlySelectedPasswordID.ToString
                Toolbox.lblPassword.Text = "**********"
                Toolbox.lblUsername.Text = Decrypt(UserKey, dsPassword.Tables(0).Rows(0).Item("Username"))
                Toolbox.lblPassword2.Text = Decrypt(UserKey, dsPassword.Tables(0).Rows(0).Item("Password"))
                Toolbox.lblWebsite.Text = Decrypt(UserKey, dsPassword.Tables(0).Rows(0).Item("WebsiteAddress"))

                If ChangeVisibilityState Then
                    Call Passwords.Status("Password has been launched in the toolbox.")
                    Passwords.WindowState = FormWindowState.Minimized
                End If


            End If

        End If

    End Sub

    Public Sub LaunchPasswordEditorOnStart(ByVal PasswordID)

        If Len(PasswordID) > 10 Then
            PasswordSelected(PasswordID)
        End If

        Passwords.txtSearch.Text = ""

    End Sub

    Public Sub SortTable(ByRef drTable As DataTable, ByVal SortString As String)

        Dim dt As DataTable
        Dim dr As DataRow
        Dim drs As DataRow()

        If drTable.Rows.Count > 1 Then
            ' make a copy, clear the original
            dt = drTable.Copy
            drTable.Clear()

            ' sort and import the data back
            drs = dt.Select(Nothing, SortString)
            For Each dr In drs
                drTable.ImportRow(dr)
            Next
        End If

        drTable.AcceptChanges()

    End Sub

   
End Module

